﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace C_高级编程
{
	/// <summary>
	/// 泛型 协变与逆变
	/// </summary>
	public class FXNX
	{
		//.net 中"泛型接口"这个概念的出现就是为了实现泛型的协变和逆变，所以当你试图创建泛型接口时，他会自动提示你要用 in 还是 out
		//只能通过泛型接口来实现协变与逆变
		//逆变和协变用的很少，只有在写框架时才会用到

		public void testFXNX()
		{
			//实现协变
			IMyList<Person> myList = new MyList<Student>();//所以，逆变和协变要通过泛型接口和他的泛型子类来实现

			IMyList<Person> myList2 = new MyList<Person>();
			IMyList<Student> myList3 = new MyList<Student>();
			myList2 = myList3;


			//实现逆变
			IMyList2<Student> myList4 = new MyList2<Person>();
			IMyList2<Student> myList5 = new MyList2<Student>();
			IMyList2<Person> myList6 = new MyList2<Person>();
			myList5 = myList6;
		}

		//系统内置协变泛型接口
		public void systemXB()
		{
			//系统自带协变接口
			IEnumerable<Person> list = new List<Student>();
		}
		

    }

	#region 协变(协变泛型接口、及其泛型实现类)
	//  协变泛型接口，必须在泛型类型参数前加out关键字，  
	//  如果是逆变，就要用 in 关键字
	/// <summary>
	/// 协变泛型接口
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public interface IMyList<out T>//out 关键字代表实现协变
	{
		public void Add();
	}


	/// <summary>
	/// 泛型子类
	/// 协变泛型接口实现类
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class MyList<T> : IMyList<T>
	{
		public void Add()
		{
			Console.WriteLine("刚刚添加了一条数据");
		}
	}
	#endregion




	#region 逆变 (逆变泛型接口，泛型实现类)
		/// <summary>
		/// 逆变泛型接口
		/// </summary>
		/// <typeparam name="T"></typeparam>
		public interface IMyList2<in T>
		{
			public void Add();
		}

		/// <summary>
		/// 泛型实现类
		/// </summary>
		/// <typeparam name="T"></typeparam>
		public class MyList2<T> : IMyList2<T>
		{
			public void Add()
			{
				Console.WriteLine("我刚刚插入了一条数据");
			}
		}
		#endregion






    /// <summary>
    /// 父类
    /// </summary>
    public class Person
	{ 
		public string Name { get; set; }

		public int Id { get; set; }

		public string FirstName { get; set; } = string.Empty;


		public virtual void Sleep()
		{
			Console.WriteLine("人类在睡觉");
		}
	}

	/// <summary>
	/// 子类
	/// </summary>
	public class Student:Person
	{
		public override void Sleep()
		{
			Console.WriteLine("学生在睡觉");
		}
	}
}
